package br.usp.ime.ingpos.web.controllers;

import java.util.List;

import org.springframework.util.StringUtils;

import br.com.caelum.vraptor.Get;
import br.com.caelum.vraptor.Path;
import br.com.caelum.vraptor.Post;
import br.com.caelum.vraptor.Resource;
import br.com.caelum.vraptor.Result;
import br.com.caelum.vraptor.Validator;
import br.com.caelum.vraptor.validator.Validations;
import br.usp.ime.ingpos.modelo.Candidato;
import br.usp.ime.ingpos.modelo.Inscricao;
import br.usp.ime.ingpos.modelo.Orientador;
import br.usp.ime.ingpos.modelo.ProcessoSeletivo;
import br.usp.ime.ingpos.modelo.TipoPerfil;
import br.usp.ime.ingpos.modelo.Usuario;
import br.usp.ime.ingpos.services.CandidatoService;
import br.usp.ime.ingpos.services.CartaDeRecomendacaoService;
import br.usp.ime.ingpos.services.InscricaoService;
import br.usp.ime.ingpos.services.InteresseService;
import br.usp.ime.ingpos.services.OrientadorService;
import br.usp.ime.ingpos.services.ProcessoSeletivoService;
import br.usp.ime.ingpos.services.UsuarioService;
import br.usp.ime.ingpos.web.interceptors.RestrictAccessPerfil;
import br.usp.ime.ingpos.web.interceptors.Transactional;

@Resource
public class CandidatoController
{
    private final Result result;
    private final UsuarioService usuarioService;
    private final Validator validador;
    private final InscricaoService inscricaoService;
    private final InteresseService interesseService;
    private final CartaDeRecomendacaoService cartaDeRecomendacaoService;
    private final OrientadorService orientadorService;
    private final ProcessoSeletivoService processoSeletivoService;
    private final UsuarioSessao usuarioSessao;
    private final CandidatoService candidatoService;

    public CandidatoController(
        final Result result,
        final Validator validador,
        final UsuarioService usuarioService,
        final InscricaoService inscricaoService,
        final CartaDeRecomendacaoService cartaDeRecomendacaoService,
        final InteresseService interesseService,
        final OrientadorService orientadorService,
        final ProcessoSeletivoService processoSeletivoService,
        final UsuarioSessao usuarioSessao,
        final CandidatoService candidatoService )

    {
        this.result = result;
        this.validador = validador;
        this.usuarioService = usuarioService;
        this.inscricaoService = inscricaoService;
        this.cartaDeRecomendacaoService = cartaDeRecomendacaoService;
        this.interesseService = interesseService;
        this.orientadorService = orientadorService;
        this.processoSeletivoService = processoSeletivoService;
        this.usuarioSessao = usuarioSessao;
        this.candidatoService = candidatoService;
    }

    @Get
    @Path( "/candidato/lista" )
    @RestrictAccessPerfil( values = {
        TipoPerfil.CANDIDATO
    } )
    public void listaCandidatos()
    {
        // AQUI NÃO FOI ESCOLHIDO NENHUM PROCESSO SELETIVO -> mostra página em
        // branco

        List<ProcessoSeletivo> processosSeletivos = processoSeletivoService.buscaProcessosSeletivosAbertos();
        result.include( "processosSeletivos", processosSeletivos );

    }

    @Get
    @Path( "/candidato/gerencia" )
    @RestrictAccessPerfil( values = {
        TipoPerfil.CANDIDATO, TipoPerfil.PROFESSOR
    } )
    public void gerenciaCandidatos()
    {
        // AQUI NÃO FOI ESCOLHIDO NENHUM PROCESSO SELETIVO -> mostra página em
        // branco

        List<ProcessoSeletivo> processosSeletivos = processoSeletivoService.buscaProcessosSeletivosAbertos();
        result.include( "processosSeletivos", processosSeletivos );

    }

    @Get
    @Path( "/candidato/atribuiOrientador" )
    @RestrictAccessPerfil( values = {
        TipoPerfil.CANDIDATO, TipoPerfil.PROFESSOR
    } )
    public void atribuiOrientador()
    {
        // AQUI NÃO FOI ESCOLHIDO NENHUM PROCESSO SELETIVO -> mostra página em
        // branco

        List<ProcessoSeletivo> processosSeletivos = processoSeletivoService.buscaProcessosSeletivosAbertos();
        result.include( "processosSeletivos", processosSeletivos );

    }

    @Get
    @Path( "/candidato/visualizar" )
    public void visualizar()
    {
        result.include( "usuario", usuarioSessao.getUsuario() );
    }

    @Get
    @Path( "/candidato/dadosPessoaisView/{hash}" )
    public void dadosPessoaisView(
        final String hash )
    {
        validador.checking( new Validations() {
            {
                that( StringUtils.hasText( hash ), "erro_visualizacao",
                    "erro_usuario_nao_encontrado" );
            }
        } );

        final Usuario usuario = usuarioService.procurarPorHash( hash );
        validador.checking( new Validations() {
            {
                that( usuario != null, "erro_visualizacao", "erro_usuario_nao_encontrado" );
            }
        } );
        validador.onErrorRedirectTo( ErroController.class ).registroNaoEncontrado();

        result.include( "usuario", usuario );
        result.include( "dadosPessoais", usuario.getDadosPessoais() );
    }

    @Post
    @Path( "/candidato/lista" )
    @RestrictAccessPerfil( values = {
        TipoPerfil.CANDIDATO
    } )
    public void listaCandidatos(
        long processoSeletivoId )
    {
        List<ProcessoSeletivo> processosSeletivos = processoSeletivoService.buscaProcessosSeletivosAbertos();

        ProcessoSeletivo processoSeletivo = processoSeletivoService.getProcessoSeletivo( processoSeletivoId );
        List<Inscricao> listaDeInscricoes = inscricaoService.getCandidatosPorProcessoSeletivo( processoSeletivo );
        List<Long> listaComInteresse = interesseService.getInscricoesComInteressePorOrientadorID(usuarioSessao.getUsuarioId());
        
        inscricaoService.verificaInscricoes(listaDeInscricoes);

        result.include( "inscricoesComInteresse", listaComInteresse);
        result.include( "processosSeletivos", processosSeletivos );
        result.include( "listaDeInscricoes", listaDeInscricoes );

    }

    @Post
    @Path( "/candidato/gerencia" )
    @RestrictAccessPerfil( values = {
        TipoPerfil.CANDIDATO, TipoPerfil.PROFESSOR
    } )
    public void gerenciaCandidatos(
        long processoSeletivoId )
    {
        List<ProcessoSeletivo> processosSeletivos = processoSeletivoService.buscaProcessosSeletivosAbertos();

        ProcessoSeletivo processoSeletivo = processoSeletivoService.getProcessoSeletivo( processoSeletivoId );
        List<Inscricao> listaDeInscricoes = inscricaoService.getCandidatosPorProcessoSeletivo( processoSeletivo );

        inscricaoService.verificaInscricoes(listaDeInscricoes);
        
        result.include( "processosSeletivos", processosSeletivos );
        result.include( "listaDeInscricoes", listaDeInscricoes );
        result.include( "processoSeletivopId", processoSeletivoId );
    }

    @Post
    @Path( "/candidato/atribuiOrientador" )
    @RestrictAccessPerfil( values = {
        TipoPerfil.CANDIDATO, TipoPerfil.PROFESSOR
    } )
    public void atribuiOrientador(
        long processoSeletivoId )
    {
        List<ProcessoSeletivo> processosSeletivos = processoSeletivoService.buscaProcessosSeletivosAbertos();

        ProcessoSeletivo processoSeletivo = processoSeletivoService.getProcessoSeletivo( processoSeletivoId );
        List<Inscricao> listaDeAprovados = inscricaoService.getCandidatosAprovadosPorProcessoSeletivo( processoSeletivo );
        List<Orientador> listaDeOrientadores = orientadorService.procurarTodosOrientadores();

        result.include( "processosSeletivos", processosSeletivos );
        result.include( "listaDeAprovados", listaDeAprovados );
        result.include( "listaDeOrientadores", listaDeOrientadores );
        result.include( "processoSeletivopId", processoSeletivoId );
    }

    @Post
    @Path( "candidato/salvaAlteracoes" )
    @Transactional
    @RestrictAccessPerfil( values = {
        TipoPerfil.CANDIDATO, TipoPerfil.PROFESSOR
    } )
    public void salvaAlteracoes(
        final List<String> aprovados,
        final List<String> reprovados,
        final List<String> conversaram,
        final List<String> naoConversaram,
        long processoSeletivoId )
    {
        inscricaoService.salvaAprovados( aprovados, reprovados );
        inscricaoService.salvaEntrevistados( conversaram, naoConversaram );
        result.include( "messages", "aprovacao_com_sucesso" );
        result.forwardTo( this ).gerenciaCandidatos();
    }

    @Post
    @Path( "candidato/salvaAtribuicoesOrientador" )
    @Transactional
    @RestrictAccessPerfil( values = {
        TipoPerfil.CANDIDATO, TipoPerfil.PROFESSOR
    } )
    public void salvaAtribuicoesOrientador(
        List<Inscricao> inscricao,
        List<String> orientadores,
        long processoSeletivoId )
    {
        String orientadoresComErro = inscricaoService.salvaOrientadores( inscricao, orientadores );
        if (orientadoresComErro.length() == 0)
        	result.include( "messages", "atribuicoes_com_sucesso" );
        else {
        	result.include( "messages", "erro_orientador_nao_encontrado");
        	result.include( "messages_param0", orientadoresComErro);
        }
        result.forwardTo( this ).atribuiOrientador();
    }

    @Post
    @Path( "candidato/salvaInteresse" )
    @Transactional
    @RestrictAccessPerfil( values = {
        TipoPerfil.CANDIDATO
    } )
    public void salvaInteresse(
        final Long idProfessor,
        final List<Long> interesse,
        final List<Long> completa )
    {
        if( completa != null ) {
            interesseService.salvaInteresse( idProfessor, interesse, completa );
        }
        result.include( "messages", "interesse_marcado_com_sucesso" );
        result.forwardTo( this ).listaCandidatos();
    }

    @Get
    @Path( "/candidato/curriculoView/{hash}" )
    public void curriculoView(
        final String hash )
    {
        validador.checking( new Validations() {
            {
                that( StringUtils.hasText( hash ), "erro_visualizacao",
                    "erro_usuario_nao_encontrado" );
            }
        } );

        final Usuario usuario = usuarioService.procurarPorHash( hash );
        validador.checking( new Validations() {
            {
                that( usuario != null, "erro_visualizacao", "erro_usuario_nao_encontrado" );
            }
        } );
        validador.onErrorRedirectTo( ErroController.class ).registroNaoEncontrado();

        result.include( "usuario", usuario );
        result.include( "curriculo", ((Candidato) usuario).getCurriculo() );
    }

    @Get
    @Path( "/candidato/inscricaoView/{hash}" )
    public void inscricaoView(
        final String hash )
    {
        validador.checking( new Validations() {
            {
                that( StringUtils.hasText( hash ), "erro_visualizacao",
                    "erro_usuario_nao_encontrado" );
            }
        } );

        final Usuario usuario = usuarioService.procurarPorHash( hash );
        validador.checking( new Validations() {
            {
                that( usuario != null, "erro_visualizacao", "erro_usuario_nao_encontrado" );
            }
        } );
        validador.onErrorRedirectTo( ErroController.class ).registroNaoEncontrado();

        result.include( "usuario", usuario );
        result.include( "inscricao", inscricaoService.getInscricaoAtual( usuario ) );
    }
    
    @Get
    @Path( "/candidato/cartasRecomendacaoView/{hash}" )
    public void cartasRecomendacaoView(
        final String hash )
    {
        validador.checking( new Validations() {
            {
                that( StringUtils.hasText( hash ), "erro_visualizacao",
                    "erro_usuario_nao_encontrado" );
            }
        } );

        final Usuario usuario = usuarioService.procurarPorHash( hash );
        validador.checking( new Validations() {
            {
                that( usuario != null, "erro_visualizacao", "erro_usuario_nao_encontrado" );
            }
        } );

        validador.onErrorRedirectTo( ErroController.class ).registroNaoEncontrado();

        result.include( "usuario", usuario );
        result.include( "cartasDeRecomendacao", cartaDeRecomendacaoService.procurarPorUsuario( usuario ) );
    }

    @Get
    @Path( "/candidato/enviaEmail" )
    @RestrictAccessPerfil( values = {
        TipoPerfil.PROFESSOR, TipoPerfil.CANDIDATO
    } )
    public void enviaEmailAprovados()
    {
        List<ProcessoSeletivo> processosSeletivos = processoSeletivoService.buscaProcessosSeletivosAbertos();
        result.include( "processosSeletivos", processosSeletivos );
    }

    @Post
    @Path( "/candidato/enviaEmail" )
    @RestrictAccessPerfil( values = {
        TipoPerfil.PROFESSOR, TipoPerfil.CANDIDATO
    } )
    public void enviaEmailAprovados(
        long processoSeletivoId )
    {
        List<ProcessoSeletivo> processosSeletivos = processoSeletivoService.buscaProcessosSeletivosAbertos();
        ProcessoSeletivo processoSeletivo = processoSeletivoService.getProcessoSeletivo( processoSeletivoId );
        List<Inscricao> listaDeInscricoes = inscricaoService.getCandidatosAprovadosPorProcessoSeletivo( processoSeletivo );

        result.include( "processosSeletivos", processosSeletivos );
        result.include( "listaDeInscricoes", listaDeInscricoes );
        result.include( "processoSeletivo", processoSeletivo );
    }

    @Post
    @Path( "/candidato/enviaEmailAprovados" )
    @Transactional
    @RestrictAccessPerfil( values = {
        TipoPerfil.PROFESSOR, TipoPerfil.CANDIDATO
    } )
    public void enviaEmailsAprovadosProcesso(
        long processoSeletivoId )
    {
        List<Inscricao> listaDeInscricoes = inscricaoService.getCandidatosAprovadosPorProcessoSeletivo( processoSeletivoService.getProcessoSeletivo( processoSeletivoId ) );
        List<Inscricao> listaDeReprovados = inscricaoService.getCandidatosReprovadosPorProcessoSeletivo( processoSeletivoService.getProcessoSeletivo( processoSeletivoId ) );
        processoSeletivoService.finalizaProcessoSeletivo( processoSeletivoService.getProcessoSeletivo( processoSeletivoId ) );
        candidatoService.enviarEmailAprovados( listaDeInscricoes );
        candidatoService.enviarEmailReprovados( listaDeReprovados );
        result.include( "messages", "email_enviado_com_sucesso" );
        result.forwardTo( this ).enviaEmailAprovados();
    }

    @Get
    @Path( "/candidato/sugereOrientando" )
    @Transactional
    @RestrictAccessPerfil( values = {
        TipoPerfil.PROFESSOR, TipoPerfil.CANDIDATO
    } )
    public void sugereOrientando(final Long inscricaoID, List<Long> orientadores)
    {
        interesseService.salvaSugestaoCoordenador( inscricaoID, orientadores);
        result.nothing();
    }
}